package cn.base.web.support.treenode;

import cn.rengy.tool.core.IdGenerator;
import cn.rengy.auth.UserService;
import cn.rengy.auth.entity.principal.Identity;
import cn.rengy.isql.DbService;
import cn.rengy.tool.core.util._LongUtil;
import cn.rengy.util.servlet.ServletUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * 有序树形
 * 实现 新增、更新、移动、复制、删除、禁用
 * @author rengy
 *
 */
@Slf4j
public abstract class OrderedTreeService<T extends TreeNode> {

	@Autowired(required = false)
	protected DbService dbService;
	@Autowired(required = false)
	protected UserService userService;


	public Map<String,Object> get(Long id){
		return this.dbService.queryForMap(this.getTreeNodeSql(),id);
	}

	public List<Map<String,Object>> comboboxList(){
		Long userId=null;
		//Long deptId=null;
		Identity identity=(Identity) ServletUtil.getPrincipal();
		if(identity!=null){
			userId=identity.getUserId();
			//SysUser sysUser=userService.getSysUser(userId);
			//deptId=sysUser.getDeptId();
		}
		Map<String,Object> param=new HashMap<String,Object>();
		param.put("userId",userId);
		//param.put("deptId",deptId);
		return this.dbService.queryForListMapParameter("select_dept_combobox",param);
	}
	public List<Map<String,Object>> selectByRootId(Long rootId){
		String tree_id=_LongUtil.toString(rootId);
		//"select_pub_class_by_tree_id"
		return this.dbService.queryForList(selectAllChildrenNodeByTreeid(), tree_id);
	}

	public List<Map<String,Object>> selectByParentId(Long parentId){
		//查询节点是否存在
		TreeNode treeNode=this.dbService.queryForBean(getTreeNodeSql(),getTClass(),parentId);
		String tree_id=null;
		if(treeNode==null){
			tree_id=_LongUtil.toString(parentId);
		}else{
			tree_id=treeNode.getTreeId();
		}
		return this.dbService.queryForList(selectAllChildrenNodeByTreeid(), tree_id);
	}

	public List<Map<String,Object>> selectByParentIdExcludeSelf(Long parentId){
		//查询节点是否存在
		TreeNode treeNode=this.dbService.queryForBean(getTreeNodeSql(),getTClass(),parentId);
		String tree_id=null;
		if(treeNode==null){
			tree_id=_LongUtil.toString(parentId);
		}else{
			tree_id=treeNode.getTreeId();
		}
		return this.dbService.queryForList(getSqlSelectByTreeidExcludeSelf(), tree_id);
	}

	
	/**
	 * 新增
	 */
	@Transactional(rollbackFor = Exception.class)
	public Long addNode(T node){
		
		setNewTreeNode(node);
		
		this.dbService.updateBeanParameter(getInsertSql(), node);
		return node.getId();
	}
	
	//protected abstract String aa();
	
	/**
	 * 新增时查询赋值TreeNode
	 * @return
	 */
	protected void setNewTreeNode(T node){
		Long id= IdGenerator.nextId();
		node.setId(id);
		Long parent_id=node.getParentId();
		String parent_tree_id="";
		TreeNode parentNode= this.dbService.queryForBean(getTreeNodeSql(), getTClass(), parent_id);
		if(parentNode==null){
			//为空就是root节点
			parent_tree_id=_LongUtil.toString(parent_id);
		}else {
			parent_tree_id=parentNode.getTreeId();
		}
		String tree_id=parent_tree_id.concat("-").concat(_LongUtil.toString(id));
		node.setTreeId(tree_id);
		
		//1.更新排序号   like '%'相当于全部查询
		int maxSortNumber=this.dbService.querySingleColumn(getMaxSortNumberByTreeIdSql(), Long.class, parent_tree_id).intValue();
		//int maxSortNumber=getMaxSortNumberByTreeId(parent_tree_id);
		node.setSortNumber(maxSortNumber+1);
		//3个参数，1：要新增节点的数量  2:rootTreeId 3:父节点的顺序号
		this.dbService.update(getMakewaySortNumberSql(),1,getRootTreeid(tree_id),maxSortNumber);
	}
	
	
	//protected  int getMaxSortNumberByTreeId(String tree_id) {
	//	return this.dbService.querySingleColumn(getMaxSortNumberByTreeIdSql(), Long.class, tree_id).intValue();
	//}
	
	
	/**
	 * 查询最大排序号
	 * @return
	 */
	//protected abstract int getMaxSortNumberByTreeId(String parent_tree_id,Object... args);
	
	/**
	 * 更新节点信息
	 */
	@Transactional(rollbackFor = Exception.class)
	public void updateNode(T node){
		Long id=node.getId();
		if(id==null) {
			return ;
		}
		Integer input_is_disabled=node.getIsDisabled();
		
		//修改时是否修改input_is_disabled字段
		if(input_is_disabled!=null){
			//查询当前状态
			TreeNode dbNode=this.dbService.queryForBean(getTreeNodeSql(), getTClass(), id);
			Integer is_disabled=dbNode.getIsDisabled();
			//禁用和启用节点同时作用到所有子节点
			//但是移动时先不考虑禁用状态
			if(is_disabled!=input_is_disabled){
				this.dbService.update(getDisableSql(),input_is_disabled,id);
			}
		}
		this.dbService.updateBeanParameter(getUpdateSql(), node);
	}



	/**
	 * 查询sql
	 * @return
	 */
	protected abstract String getSelectSql();

	/**
	 * 查询sql排除自己
	 * @return
	 */
	protected abstract String getSelectSqlExcludeSelf();
	/**
	 * 删除sql
	 * @return
	 */
	protected abstract String getUpdateSql();
	
	/**
	 * 新增sql
	 * @return
	 */
	protected abstract String getInsertSql();
	
	/**
	 * 复制新增sql
	 * @return
	 */
	protected abstract String getCopyInsertSql();
	
	/**
	 * 删除sql
	 * @return
	 */
	protected abstract String getDeleteSql();
	
	/**
	 * 删除节点
	 */
	public void delete(Long id) {
		if(id!=null) {
			this.dbService.update(getDeleteSql(), id);
		}
	}
	
	/**
	 * 禁用sql
	 * @return
	 */
	protected abstract String getDisableSql();
	
	/**
	 * 禁用节点
	 */
	public void disable(Long id) {
		this.dbService.update(getDisableSql(),1, id);
	}
	
	
	/**
	 * 启用节点
	 */
	public void enable(Long id) {
		this.dbService.update(getDisableSql(),0, id);
	}
	/**
	 *  //Type type = getClass().getGenericSuperclass();
		//Type[] t=((ParameterizedType)type).getActualTypeArguments();
		//TClass = (Class<T>) t[0];
	 * @return
	 */
	protected abstract Class<TreeNode> getTClass();
	
	
	private List<TreeNode> toTree(List<TreeNode> nodeList) {
		List<TreeNode> newList=new ArrayList<TreeNode>();
		//寻找根节点  ，单节点复制第一个节点就是根节点
		TreeNode firstNode=nodeList.remove(0);
		newList.add(firstNode);
		//递归查询子节点
		findChildren(newList,nodeList);
		return newList;
	}
	
	/**
	 * 把tree转出平铺类型,
	 * @return
	 */
	private void toFlat(List<TreeNode> children,List<TreeNode> newList) {
		if(children!=null&&children.size()>0) {
			for(int i=0;i<children.size();i++) {
				TreeNode node=children.get(i);
				List<TreeNode> nodeChildren=   node.getChildren();
				//删除原有的children
				node.setChildren(null);
				newList.add(node);
				toFlat(nodeChildren,newList);
			}
		}
	}
	//递归查询子节点
	private void findChildren(List<TreeNode> childrenList,List<TreeNode> sourceList) {
		if(sourceList!=null&&sourceList.size()>0) {
			if(childrenList!=null&&childrenList.size()>0) {
				for(int i=0;i<childrenList.size();i++) {
					TreeNode newNode=childrenList.get(i);
					List<TreeNode> children=  newNode.getChildren();
					for(int j=0;j<sourceList.size();j++) {
						TreeNode sourceNode=sourceList.get(j);
						if(sourceNode.getParentId().equals(newNode.getId())) {
							if(children==null) {
								children=new ArrayList<TreeNode>();
								newNode.setChildren(children);
							}
							children.add(sourceNode);
							sourceList.remove(j);
							j--;
						}
					}
					findChildren(children,sourceList);
				}
			}
		}
	}
	
	private void onCopyUpdateTreeId(Long parentId,String parentTreeId,List<TreeNode> treeList){
		if(treeList!=null&&treeList.size()>0) {
			for(int i=0;i<treeList.size();i++) {
				TreeNode node=treeList.get(i);
				node.setId(IdGenerator.nextId());
				node.setParentId(parentId);
				node.setTreeId(parentTreeId.concat("-").concat(_LongUtil.toString(node.getId())));
				onCopyUpdateTreeId(node.getId(),node.getTreeId(),  node.getChildren());
			}
		}
	}
	/**
	 * 移动时更新treeid
	 * @param parentTreeId
	 * @param treeList
	 */
	private void onMoveUpdateTreeNode(String parentTreeId,List<TreeNode> treeList){
		if(treeList!=null&&treeList.size()>0) {
			for(int i=0;i<treeList.size();i++) {
				TreeNode node=treeList.get(i);
				node.setTreeId(parentTreeId.concat("-").concat(_LongUtil.toString(node.getId())));
				onMoveUpdateTreeNode(node.getTreeId(),  node.getChildren());
			}
		}
	}
	
	/**
	 * 根据treeid查询父级的treeid
	 * @param treeid
	 * @return
	 */
	private String getParentTreeid(String treeid) {
		int lastIndex=treeid.lastIndexOf("-");
		int endIndex=lastIndex==-1?treeid.length():lastIndex;
		return treeid.substring(0,endIndex);
	}
	/**
	 * 根据treeid查询RootTreeid
	 * @param treeid
	 * @return
	 */
	private String getRootTreeid(String treeid) {
		int index=treeid.indexOf("-");
		int endIndex=(index==-1)?treeid.length():index;
		return treeid.substring(0,endIndex);
	}

	/**
	 * 单节点复制
	 * 复制为 同级后一个节点
	 */
	@Transactional(rollbackFor = Exception.class)
	public void copy(Long target_id){
		TreeNode targetNode= this.dbService.queryForBean(getTreeNodeSql(), getTClass(), target_id);
		if(targetNode==null) {
			throw new IllegalArgumentException("不能复制此节点");
		}
		//要移动的所有节点
		List<TreeNode> moveList=this.dbService.queryForBeanList(selectAllChildrenNodeById(), getTClass(), target_id);
		
		String targetTreeId=targetNode.getTreeId();
		//查询目标节点子节点最大sort_number，
		int maxSortNumber=this.dbService.querySingleColumn(getMaxSortNumberByTreeIdSql(), Long.class, targetTreeId).intValue();
		//int maxSortNumber=getMaxSortNumberByTreeId(targetTreeId,targetNode);
		//1.先把目标节点后的所有节点序号更新为(子节点最大+移动节点数量)
		String rootTreeId=getRootTreeid(targetTreeId);
		this.dbService.update(getMakewaySortNumberSql(), moveList.size(),rootTreeId,maxSortNumber);
		//2.更新新节点的顺序号
		//同时更新第一个节点的名称
		TreeNode firstNode=moveList.get(0);
		firstNode.setNodeName(firstNode.getNodeName()+"Copy");
		for(int i=0,j=maxSortNumber;i<moveList.size();i++){
			TreeNode childNode=moveList.get(i);
			childNode.setSortNumber(++j);
		}
		//3.转换成tree结构
		List<TreeNode> treeList=toTree(moveList);
		//4.更新id tree_id parent_id
		onCopyUpdateTreeId(targetNode.getParentId(),getParentTreeid(targetNode.getTreeId()),treeList);
		//5.转换成平铺结构  这时候的moveList已经空了
		moveList.clear();
		toFlat(treeList,moveList);
		//6.保存到数据库
		this.dbService.batchUpdateBeanParameter(getCopyInsertSql(), moveList);
	}
	/**
	 * 单节点移动
	 * @param param
	 */
	@Transactional(rollbackFor = Exception.class)
	public void move(PubCategoryMoveVO param){
		Long move_node_id=param.getNode();//待移动节点
		Long target_id=param.getTarget();//目标节点
		//"inner"：成为子节点，"prev"：成为同级前一个节点，"next"：成为同级后一个节点
		String moveType=param.getMoveType();
		Assert.notNull(moveType,"moveType must not be null");
		
		//要移动的所有节点
		List<TreeNode> moveList= this.dbService.queryForBeanList(selectAllChildrenNodeById(), getTClass(), move_node_id);
		TreeNode firstMoved=moveList.get(0);
		//目标节点
		TreeNode targetNode= this.dbService.queryForBean(getTreeNodeSql(), getTClass(), target_id);
		String targetTreeId="";//目标节点tree_id
		if(targetNode==null) {//根节点
			//查不到目标节点则为root节点
			targetTreeId=_LongUtil.toString(target_id);
			
			if(moveType.equals("prev")||moveType.equals("next")){//成为同级节点
				throw new IllegalArgumentException("不能移动到根节点的同级节点,只能有一个根节点");
			}
		}else {
			
			targetTreeId=targetNode.getTreeId();
		}
		String rootTreeId=getRootTreeid(targetTreeId);
		//成为后面节点，子节点或者成为同级后一个节点
		int maxSortNumber=0;
		if(moveType.equals("inner")||moveType.equals("next")){
			//查询目标节点子节点最大sort_number，
			maxSortNumber=this.dbService.querySingleColumn(getMaxSortNumberByTreeIdSql(), Long.class, targetTreeId).intValue();
			//maxSortNumber=getMaxSortNumberByTreeId(targetTreeId,move_node);
			//1.先把目标节点后的所有节点序号更新为(子节点最大+移动节点数量)
			this.dbService.update(getMakewaySortNumberSql(), moveList.size(),rootTreeId,maxSortNumber);
			//更新节点的顺序号
			for(int i=0,j=maxSortNumber;i<moveList.size();i++) {
				TreeNode childNode=moveList.get(i);
				childNode.setSortNumber(++j);
			}
		}else if(moveType.equals("prev")) {//成为同级前一个节点
			/**
			 * 父节点是target的父节点
			 * 把target节点和之后的节点sort_number+移动节点数量
			 * 
			 * */
			this.dbService.update(getMakewaySortNumberSql(),moveList.size(),rootTreeId,targetNode.getSortNumber()-1);
			//更新顺序号
			for(int i = 0, j = targetNode.getSortNumber(); i<moveList.size(); i++) {
				TreeNode childNode=moveList.get(i);
				childNode.setSortNumber(j++);
			}
		}
		//更新父id
		String movedTreeId=null;//节点移动的父treeid
		if(moveType.equals("inner")){//成为子节点
			firstMoved.setParentId(target_id);
			movedTreeId=targetTreeId;
		}else if(moveType.equals("prev")||moveType.equals("next")){//成为同级
			firstMoved.setParentId(targetNode.getParentId());
			movedTreeId=this.getParentTreeid(targetTreeId);
		}
		//3.转换成tree结构
		List<TreeNode> treeList=toTree(moveList);
		//4.更新 tree_id
		onMoveUpdateTreeNode(movedTreeId,treeList);
		//5.转换成平铺结构  这时候的moveList已经空了
		//moveList.clear();
		toFlat(treeList,moveList);
		this.dbService.batchUpdateBeanParameter(getUpdateMoveSql(), moveList);
	}
	
	/**
	 * 查询待copy的节点，查询所有字段信息
	 * @return
	 */
	protected abstract String selectAllChildrenNodeByTreeid();

	/**
	 * 不包含自己
	 * @return
	 */
	protected abstract String getSqlSelectByTreeidExcludeSelf();
	
	/**
	 * 查询id查询所有子节点
	 * @return
	 */
	protected abstract String selectAllChildrenNodeById();
	
	/**
	 * 查询待移动的节点
	 * @return
	 */
	protected abstract String getTreeNodeSql();
	
	/**
	 * 查询节点最大序号
	 * @return
	 */
	protected abstract String getMaxSortNumberByTreeIdSql();
	
	
	/**
	 * 更新树形的sortNumber，给移动后的节点腾出顺序号
	 * @return
	 */
	protected abstract String getMakewaySortNumberSql();
	
	
	protected abstract String getUpdateMoveSql();
	
}
